4  PBMCs: Define “Post-Nivolumab” Clones

4.1 Set up workspace

# Load libraries
library(dplyr)

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ forcats   1.0.0     ✔ readr     2.1.5
✔ ggplot2   3.5.1     ✔ stringr   1.5.1
✔ lubridate 1.9.4     ✔ tibble    3.2.1
✔ purrr     1.0.4     ✔ tidyr     1.3.1
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
# Function to calculate the lower limit of detection
lod <- function(dat){
  10^(floor(log10(min(dat, na.rm = TRUE))))
}

4.2 Defintion of post-nivo expanded clones in PBMCs

  1. Quality control metric: the clone must have 3 or more UMI in at least one time point
  2. Below the limit of detection at the pre-treatment timepoint
  3. 10x the lower limit of detection at the pre-vax timepoint

  4. Present at all time points after pre-vax

4.3 Load PBMC data

p101_betas <- read.csv("p101_betas_merged_Part1.csv")
p103_betas <- read.csv("p103_betas_merged_Part1.csv")
p104_betas <- read.csv("p104_betas_merged_Part1.csv")
p105_betas <- read.csv("p105_betas_merged_Part1.csv")
p106_betas <- read.csv("p106_betas_merged_Part1.csv")
p108_betas <- read.csv("p108_betas_merged_Part1.csv")
p109_betas <- read.csv("p109_betas_merged_Part1.csv")
p110_betas <- read.csv("p110_betas_merged_Part1.csv")
p111_betas <- read.csv("p111_betas_merged_Part1.csv")

4.4 Update undetected values

# Calculate the lower limit of detection on the longitudinal samples before any clones are filtered
p101_pretreatment_lod <- lod(p101_betas$p101_pretreatment)
p101_prevax_lod <- lod(p101_betas$p101_prevax)
p101_postvax_lod <- lod(p101_betas$p101_postvax)

p103_pretreatment_lod <- lod(p103_betas$p103_pretreatment)
p103_prevax_lod <- lod(p103_betas$p103_prevax)
p103_postvax_lod <- lod(p103_betas$p103_postvax)
p103_w48_lod <- lod(p103_betas$p103_w48)
p103_w72_lod <- lod(p103_betas$p103_w72)

p104_pretreatment_lod <- lod(p104_betas$p104_pretreatment)
p104_prevax_lod <- lod(p104_betas$p104_prevax)
p104_postvax_lod <- lod(p104_betas$p104_postvax)
p104_w48_lod <- lod(p104_betas$p104_w48)

p105_pretreatment_lod <- lod(p105_betas$p105_pretreatment)
p105_prevax_lod <- lod(p105_betas$p105_prevax)
p105_postvax_lod <- lod(p105_betas$p105_postvax)
p105_w48_lod <- lod(p105_betas$p105_w48)

p106_pretreatment_lod <- lod(p106_betas$p106_pretreatment)
p106_prevax_lod <- lod(p106_betas$p106_prevax)
p106_postvax_lod <- lod(p106_betas$p106_postvax)
p106_w48_lod <- lod(p106_betas$p106_w48)

p108_pretreatment_lod <- lod(p108_betas$p108_pretreatment)
p108_prevax_lod <- lod(p108_betas$p108_prevax)
p108_postvax_lod <- lod(p108_betas$p108_postvax)
p108_w32_lod <- lod(p108_betas$p108_w32)

p109_pretreatment_lod <- lod(p109_betas$p109_pretreatment)
p109_prevax_lod <- lod(p109_betas$p109_prevax)
p109_postvax_lod <- lod(p109_betas$p109_postvax)
p109_w48_lod <- lod(p109_betas$p109_w48)

p110_pretreatment_lod <- lod(p110_betas$p110_pretreatment)
p110_prevax_lod <- lod(p110_betas$p110_prevax)
p110_postvax_lod <- lod(p110_betas$p110_postvax)
p110_w38_lod <- lod(p110_betas$p110_w38)

p111_pretreatment_lod <- lod(p111_betas$p111_pretreatment)
p111_prevax_lod <- lod(p111_betas$p111_prevax)
p111_postvax_lod <- lod(p111_betas$p111_postvax)
p111_w40_lod <- lod(p111_betas$p111_w40)

# Update undetected values to the LOD to simplify longitudinal frequency plots
p101_betas <- p101_betas %>%
  mutate(p101_pretreatment = replace_na(p101_pretreatment, p101_pretreatment_lod),
         p101_prevax = replace_na(p101_prevax, p101_prevax_lod),
         p101_postvax = replace_na(p101_postvax, p101_postvax_lod))

p103_betas <- p103_betas %>%
  mutate(p103_pretreatment = replace_na(p103_pretreatment, p103_pretreatment_lod),
         p103_prevax = replace_na(p103_prevax, p103_prevax_lod),
         p103_postvax = replace_na(p103_postvax, p103_postvax_lod),
         p103_w48 = replace_na(p103_w48, p103_w48_lod),
         p103_w72 = replace_na(p103_w72, p103_w72_lod)
         )
p104_betas <- p104_betas %>%
  mutate(p104_pretreatment = replace_na(p104_pretreatment, p104_pretreatment_lod),
         p104_prevax = replace_na(p104_prevax, p104_prevax_lod),
         p104_postvax = replace_na(p104_postvax, p104_postvax_lod),
         p104_w48 = replace_na(p104_w48, p104_w48_lod))
p105_betas <- p105_betas %>%
  mutate(p105_pretreatment = replace_na(p105_pretreatment, p105_pretreatment_lod),
         p105_prevax = replace_na(p105_prevax, p105_prevax_lod),
         p105_postvax = replace_na(p105_postvax, p105_postvax_lod),
         p105_w48 = replace_na(p105_w48, p105_w48_lod))
p106_betas <- p106_betas %>%
  mutate(p106_pretreatment = replace_na(p106_pretreatment, p106_pretreatment_lod),
         p106_prevax = replace_na(p106_prevax, p106_prevax_lod),
         p106_postvax = replace_na(p106_postvax, p106_postvax_lod),
         p106_w48 = replace_na(p106_w48, p106_w48_lod))
p108_betas <- p108_betas %>%
  mutate(p108_pretreatment = replace_na(p108_pretreatment, p108_pretreatment_lod),
         p108_prevax = replace_na(p108_prevax, p108_prevax_lod),
         p108_postvax = replace_na(p108_postvax, p108_postvax_lod),
         p108_w32 = replace_na(p108_w32, p108_w32_lod))
p109_betas <- p109_betas %>%
  mutate(p109_pretreatment = replace_na(p109_pretreatment, p109_pretreatment_lod),
         p109_prevax = replace_na(p109_prevax, p109_prevax_lod),
         p109_postvax = replace_na(p109_postvax, p109_postvax_lod),
         p109_w48 = replace_na(p109_w48, p109_w48_lod))
p110_betas <- p110_betas %>%
  mutate(p110_pretreatment = replace_na(p110_pretreatment, p110_pretreatment_lod),
         p110_prevax = replace_na(p110_prevax, p110_prevax_lod),
         p110_postvax = replace_na(p110_postvax, p110_postvax_lod),
         p110_w38 = replace_na(p110_w38, p110_w38_lod))
p111_betas <- p111_betas %>%
  mutate(p111_pretreatment = replace_na(p111_pretreatment, p111_pretreatment_lod),
         p111_prevax = replace_na(p111_prevax, p111_prevax_lod),
         p111_postvax = replace_na(p111_postvax, p111_postvax_lod),
         p111_w40 = replace_na(p111_w40, p111_w40_lod))

4.5 Implement quality control metric: each clone must have 3 or more UMI in at least one time point

p101_betas_qc <- p101_betas %>%
  filter(p101_pretreatment_umi >= 3 | p101_prevax_umi >= 3 | p101_postvax_umi >= 3)

p103_betas_qc <- p103_betas %>%
  filter(p103_pretreatment_umi >= 3 | p103_prevax_umi >= 3 | p103_postvax_umi >= 3 | p103_w48_umi >= 3 | p103_w72_umi >= 3)

p104_betas_qc <- p104_betas %>%
  filter(p104_pretreatment_umi >= 3 | p104_prevax_umi >= 3 | p104_postvax_umi >= 3 | p104_w48_umi >= 3)

p105_betas_qc <- p105_betas %>%
  filter(p105_pretreatment_umi >= 3 | p105_prevax_umi >= 3 | p105_postvax_umi >= 3 | p105_w48_umi >= 3)

p106_betas_qc <- p106_betas %>%
  filter(p106_pretreatment_umi >= 3 | p106_prevax_umi >= 3 | p106_postvax_umi >= 3 | p106_w48_umi >= 3)

p108_betas_qc <- p108_betas %>%
  filter(p108_pretreatment_umi >= 3 | p108_prevax_umi >= 3 | p108_postvax_umi >= 3 | p108_w32_umi >= 3)

p109_betas_qc <- p109_betas %>%
  filter(p109_pretreatment_umi >= 3 | p109_prevax_umi >= 3 | p109_postvax_umi >= 3 | p109_w48_umi >= 3)

p110_betas_qc <- p110_betas %>%
  filter(p110_pretreatment_umi >= 3 | p110_prevax_umi >= 3 | p110_postvax_umi >= 3 | p110_w38_umi >= 3)

p111_betas_qc <- p111_betas %>%
  filter(p111_pretreatment_umi >= 3 | p111_prevax_umi >= 3 | p111_postvax_umi >= 3 | p111_w40_umi >= 3)

4.6 Implement timepoint filter: Clones must be below (technically at, given the earlier conversion of undetected values to the LOD) the limit of detection at the pre-treatment timepoint

p101_betas_tp <- p101_betas_qc %>%
  filter(p101_pretreatment == p101_pretreatment_lod)

p103_betas_tp <- p103_betas_qc %>%
  filter(p103_pretreatment == p103_pretreatment_lod)

p104_betas_tp <- p104_betas_qc %>%
  filter(p104_pretreatment == p104_pretreatment_lod)

p105_betas_tp <- p105_betas_qc %>%
  filter(p105_pretreatment == p105_pretreatment_lod)

p106_betas_tp <- p106_betas_qc %>%
  filter(p106_pretreatment == p106_pretreatment_lod)

p108_betas_tp <- p108_betas_qc %>%
  filter(p108_pretreatment == p108_pretreatment_lod)

p109_betas_tp <- p109_betas_qc %>%
  filter(p109_pretreatment == p109_pretreatment_lod)

p110_betas_tp <- p110_betas_qc %>%
  filter(p110_pretreatment == p110_pretreatment_lod)

p111_betas_tp <- p111_betas_qc %>%
  filter(p111_pretreatment == p111_pretreatment_lod)

4.7 Implement expression filter: >10x the lower limit of detection at the pre-vax timepoint

p101_betas_exp <- p101_betas_tp %>%
  filter(p101_prevax > p101_prevax_lod*10)

p103_betas_exp <- p103_betas_tp %>%
  filter(p103_prevax > p103_prevax_lod*10)

p104_betas_exp <- p104_betas_tp %>%
  filter(p104_prevax > p104_prevax_lod*10)

p105_betas_exp <- p105_betas_tp %>%
  filter(p105_prevax > p105_prevax_lod*10)

p106_betas_exp <- p106_betas_tp %>%
  filter(p106_prevax > p106_prevax_lod*10)

p108_betas_exp <- p108_betas_tp %>%
  filter(p108_prevax > p108_prevax_lod*10)

p109_betas_exp <- p109_betas_tp %>%
  filter(p109_prevax > p109_prevax_lod*10)

p110_betas_exp <- p110_betas_tp %>%
  filter(p110_prevax > p110_prevax_lod*10)

p111_betas_exp <- p111_betas_tp %>%
  filter(p111_prevax > p111_prevax_lod*10)

4.8 Implement secondary expression filter: Present at all time points after pre-vax

p101_betas_pres <- p101_betas_exp %>%
  filter(p101_postvax > p101_postvax_lod)

p103_betas_pres <- p103_betas_exp %>%
  filter(p103_postvax > p103_postvax_lod,
         p103_w48 > p103_w48_lod,
         p103_w72 > p103_w72_lod)

p104_betas_pres <- p104_betas_exp %>%
  filter(p104_postvax > p104_postvax_lod,
         p104_w48 > p104_w48_lod)

p105_betas_pres <- p105_betas_exp %>%
  filter(p105_postvax > p105_postvax_lod,
         p105_w48 > p105_w48_lod)

p106_betas_pres <- p106_betas_exp %>%
  filter(p106_postvax > p106_postvax_lod,
         p106_w48 > p106_w48_lod)

p108_betas_pres <- p108_betas_exp %>%
  filter(p108_postvax > p108_postvax_lod,
         p108_w32 > p108_w32_lod)

p109_betas_pres <- p109_betas_exp %>%
  filter(p109_postvax > p109_postvax_lod,
         p109_w48 > p109_w48_lod)

p110_betas_pres <- p110_betas_exp %>%
  filter(p110_postvax > p110_postvax_lod,
         p110_w38 > p110_w38_lod)

p111_betas_pres <- p111_betas_exp %>%
  filter(p111_postvax > p111_postvax_lod,
         p111_w40 > p111_w40_lod)

4.9 Save the “Post-Nivolumab” beta clonotypes

# Add a column for patient
p101_betas_pres <- p101_betas_pres %>%
  mutate(Patient = "P101")
p103_betas_pres <- p103_betas_pres %>%
  mutate(Patient = "P103")
p104_betas_pres <- p104_betas_pres %>%
  mutate(Patient = "P104")
p105_betas_pres <- p105_betas_pres %>%
  mutate(Patient = "P105")
p106_betas_pres <- p106_betas_pres %>%
  mutate(Patient = "P106")
p108_betas_pres <- p108_betas_pres %>%
  mutate(Patient = "P108")
p109_betas_pres <- p109_betas_pres %>%
  mutate(Patient = "P109")
p110_betas_pres <- p110_betas_pres %>%
  mutate(Patient = "P110")
p111_betas_pres <- p111_betas_pres %>%
  mutate(Patient = "P111")

post_nivo_betas_pres <- do.call(rbind, list(p101_betas_pres[,c("Beta_clonotype", "Patient")],
                                          p103_betas_pres[,c("Beta_clonotype", "Patient")],
                                          p104_betas_pres[,c("Beta_clonotype", "Patient")],
                                          p105_betas_pres[,c("Beta_clonotype", "Patient")],
                                          p106_betas_pres[,c("Beta_clonotype", "Patient")],
                                          p108_betas_pres[,c("Beta_clonotype", "Patient")],
                                          p109_betas_pres[,c("Beta_clonotype", "Patient")],
                                          p110_betas_pres[,c("Beta_clonotype", "Patient")],
                                          p111_betas_pres[,c("Beta_clonotype", "Patient")]))

write.csv(post_nivo_betas_pres, "PBMC_Post-Nivolumab_Beta_Chains_Part2.csv")

4.10 Get session Info

sessionInfo()
R version 4.3.2 (2023-10-31)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Rocky Linux 8.10 (Green Obsidian)

Matrix products: default
BLAS/LAPACK: /usr/lib64/libopenblasp-r0.3.15.so;  LAPACK version 3.9.0

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

time zone: America/New_York
tzcode source: system (glibc)

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] lubridate_1.9.4 forcats_1.0.0   stringr_1.5.1   purrr_1.0.4    
 [5] readr_2.1.5     tidyr_1.3.1     tibble_3.2.1    ggplot2_3.5.1  
 [9] tidyverse_2.0.0 dplyr_1.1.4    

loaded via a namespace (and not attached):
 [1] gtable_0.3.6      jsonlite_1.8.9    compiler_4.3.2    tidyselect_1.2.1 
 [5] scales_1.3.0      fastmap_1.2.0     R6_2.6.1          generics_0.1.3   
 [9] knitr_1.49        htmlwidgets_1.6.4 munsell_0.5.1     pillar_1.10.1    
[13] tzdb_0.5.0        rlang_1.1.5       stringi_1.8.4     xfun_0.50        
[17] timechange_0.3.0  cli_3.6.3         withr_3.0.2       magrittr_2.0.3   
[21] digest_0.6.37     grid_4.3.2        rstudioapi_0.17.1 hms_1.1.3        
[25] lifecycle_1.0.4   vctrs_0.6.5       evaluate_1.0.1    glue_1.8.0       
[29] colorspace_2.1-1  rmarkdown_2.29    tools_4.3.2       pkgconfig_2.0.3  
[33] htmltools_0.5.8.1